
//; ---------------------------------------------------------------------------
//; Object 0D - signpost at the end of a level
//; ---------------------------------------------------------------------------

#include "signpost.h"
#include "rings.h"
#include "gotthroughcard.h"

#include "../sprite.h"
#include "../objectsystemNEWER.h"
#include "../joypad.h"
#include "../plcsystem.h"

static object *obj;

//EXTERN DEFINITIONS HERE
#define player objects[0]
extern object *objects;
extern byte *Map_Ring[8];

extern byte f_timecount;
extern word v_limitleft2;
extern word v_limitright2;
extern word v_debuguse;
extern bool f_lockctrl;
extern byte v_jpadhold2;
extern byte v_invinc;
extern byte v_timeP[4];
#define v_timemin v_timeP[1]  
#define v_timesec v_timeP[2] 
#define v_timecent v_timeP[3]
extern word v_timebonus;
extern word v_ringbonus;
extern word v_rings;
extern byte f_endactbonus;

//; ---------------------------------------------------------------------------
//; Animation script - signpost
//; ---------------------------------------------------------------------------
byte _signeggman[3] = { 0xF, 0, afEnd };
byte _signspin1[6] = { 1, 0, 1, 2, 3, afEnd };
byte _signspin2[6] = { 1, 4, 1, 2, 3, afEnd };
byte _signsonic[3] = { 0xF, 4, afEnd };

byte *Ani_Sign[4] = { _signeggman, _signspin1, _signspin2, _signsonic };	

//; ---------------------------------------------------------------------------
//; Sprite mappings - signpost
//; ---------------------------------------------------------------------------
byte signeggman[16] = { 3,
		 0xF0, 0xB, 0,    0, 0xE8,
		 0xF0, 0xB, 8,    0,    0,
		 0x10,   1, 0, 0x38, 0xFC
};

byte signspin1[11] = { 2,
		 0xF0, 0xF, 0,  0xC, 0xF0,
		 0x10,   1, 0, 0x38, 0xFC
};
byte signspin2[11] = { 2,
		 0xF0,   3, 0, 0x1C, 0xFC,
		 0x10,   1, 8, 0x38, 0xFC
};
byte signspin3[11] = { 2,
		 0xF0, 0xF, 8,  0xC, 0xF0,
		 0x10,   1, 8, 0x38, 0xFC
};
byte signsonic[16] = { 3,
		 0xF0, 0xB, 0, 0x20, 0xE8,
		 0xF0, 0xB, 0, 0x2C,    0,
		 0x10,   1, 0, 0x38, 0xFC
};

byte *Map_Sign[5] = { signeggman, signspin1, signspin2, signspin3, signsonic };

//==========

void (*Sign_Index[5])() = { Sign_Main, Sign_Touch, Sign_Spin, Sign_SonicRun, Sign_Exit };

//OBJECT:					; XREF: Obj_Index
void Signpost(object *_obj)
{
    obj = _obj;

    //moveq	#0,d0
    //move.b	obRoutine(a0),d0
    byte routine = obj->Routine/2;

    //move.w	Sign_Index(pc,d0.w),d1
    //jsr	Sign_Index(pc,d1.w)
    (*Sign_Index[routine])();

    //lea	(Ani_Sign).l,a1
    byte **aniScript = Ani_Sign;

    //bsr.w	AnimateSprite
    AnimateSprite(obj, aniScript);

    //bsr.w	DisplaySprite
    DisplaySprite(obj);

    //out_of_range	DeleteObject
    if (out_of_range(obj)) { DeleteObject(obj); }
}

//; ===========================================================================

//spintime:	= $30		; time for signpost to spin
#define spintime 0x30

//sparkletime:	= $32		; time between sparkles
#define sparkletime 0x32

//sparkle_id:	= $34		; counter to keep track of sparkles
#define sparkle_id 0x34

//Sign_Main:	; Routine 0
void Sign_Main()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;

    //move.l	#Map_Sign,obMap(a0)
    obj->Map = Map_Sign;

    //move.w	#$680,obGfx(a0)
    obj->Gfx = 0x680;

    //move.b	#4,obRender(a0)
    obj->Render = 4;

    //move.b	#$18,obActWid(a0)
    obj->ActionWidth = 0x18;

    //move.b	#4,obPriority(a0)
    obj->Priority = 4;

}

//Sign_Touch:	; Routine 2
void Sign_Touch()
{
    //move.w	(v_player+obX).w,d0
    word playerX = player.X;

    //sub.w	obX(a0),d0
    signed short distPlayerObj = playerX - obj->X;

    //bcs.s	@notouch
    if (distPlayerObj > 0)
    {
	//cmpi.w	#$20,d0		; is Sonic within $20 pixels of	the signpost?
        //bcc.s	@notouch	; if not, branch
        if (distPlayerObj < 0x20)
        {
	    //music	sfx_Signpost	; play signpost sound
	    //clr.b	(f_timecount).w	; stop time counter
            f_timecount = 0;

	    //move.w	(v_limitright2).w,(v_limitleft2).w ; lock screen position
            v_limitleft2=v_limitright2;            

	    //addq.b	#2,obRoutine(a0)
            obj->Routine = obj->Routine + 2;
        }
    }
	    //@notouch:
}	    //rts	
//; ===========================================================================

signed char Sign_SparkPos[16] = { -0x18, -0x10, // ; x-position, y-position
                                      8,     8,
                                   0x10,     0,
		                   0x18,     8,
                                      0,    -8,
        		           0x10,     0,
 		                  -0x18,     8,
		                   0x18,  0x10
};

//Sign_Spin:	; Routine 4
void Sign_Spin()
{
    //subq.w	#1,spintime(a0)	; subtract 1 from spin time
    ptrsubobjvariableword(spintime,obj,1);

    //bpl.s	@chksparkle	; if time remains, branch
    if ((signed short)ptrgetobjvariableword(spintime,obj) < 0)
    {
        //move.w	#60,spintime(a0) ; set spin cycle time to 1 second
        ptrsetobjvariableword(spintime,obj,60);

	//addq.b	#1,obAnim(a0)	; next spin cycle
        obj->Anim = obj->Anim + 1;
	
        //cmpi.b	#3,obAnim(a0)	; have 3 spin cycles completed?
        //bne.s	@chksparkle	; if not, branch
        if (obj->Anim ==3)
        {
	    //addq.b	#2,obRoutine(a0)
            obj->Routine = obj->Routine + 2;
        }
    }

    //@chksparkle:
    //subq.w	#1,sparkletime(a0) ; subtract 1 from time delay
    ptrsubobjvariableword(sparkletime,obj,1);

    //bpl.s	@fail		; if time remains, branch
    if ((signed short)ptrgetobjvariableword(sparkletime, obj) < 0)
    { 
        //move.w	#$B,sparkletime(a0) ; set time between sparkles to $B frames
        ptrsetobjvariableword(sparkletime, obj, 0xB)
       
	//moveq	#0,d0
        //move.b	sparkle_id(a0),d0 ; get sparkle id
        byte sparkleid = obj->Variables[sparkle_id-0x28];

        //addq.b	#2,sparkle_id(a0) ; increment sparkle counter
        obj->Variables[sparkle_id-0x28] = obj->Variables[sparkle_id-0x28] + 2;

	//andi.b	#$E,sparkle_id(a0)
        obj->Variables[sparkle_id-0x28] = obj->Variables[sparkle_id-0x28] & 0xE;

	//lea	Sign_SparkPos(pc,d0.w),a2 ; load sparkle position data
        signed char *sparklePosition = &Sign_SparkPos[sparkleid];

	//bsr.w	FindFreeObj
        object *rings = FindFreeObj();

	//bne.s	@fail
        if (rings->ID == 0)
        {
	    //move.b	#id_Rings,0(a1)	; load rings object
            rings->ID = id_Rings;

            #define id_Ring_Sparkle 6
            //move.b	#id_Ring_Sparkle,obRoutine(a1) ; jump to ring sparkle subroutine
            rings->Routine = id_Ring_Sparkle;

	    //move.b	(a2)+,d0
	    //ext.w	d0
            signed short xpos = *(sparklePosition++);

	    //add.w	obX(a0),d0
            word postxpos = obj->X + xpos;

	    //move.w	d0,obX(a1)
            rings->X = postxpos;

	    //move.b	(a2)+,d0
            //ext.w	d0
            signed short ypos = *(sparklePosition++);

	    //add.w	obY(a0),d0
            word postypos = obj->Y + ypos;
 
	    //move.w	d0,obY(a1)
            rings->Y = postypos;

	    //move.l	#Map_Ring,obMap(a1)
            rings->Map = Map_Ring;

       	    //move.w	#$27B2,obGfx(a1)
            rings->Gfx = 0x27B2;

	    //move.b	#4,obRender(a1)
            rings->Render = 4;

	    //move.b	#2,obPriority(a1)
            rings->Priority = 2;

	    //move.b	#8,obActWid(a1)
            rings->ActionWidth = 8;
        }
    }
    //@fail:
    //rts	
}
//; ===========================================================================

//; ===========================================================================

//Sign_SonicRun:	; Routine 6
void Sign_SonicRun()
{
    //tst.w	(v_debuguse).w	; is debug mode	on?
    if (v_debuguse == 0)
    {   // bne.w	locret_ECEE	; if yes, branch
	
        //btst	#1,(v_player+obStatus).w
        //bne.s	loc_EC70
        if ((player.Status & 2) == 0)
        {
		 //move.b	#1,(f_lockctrl).w ; lock controls
                f_lockctrl = 1;
		
                //move.w	#btnR<<8,(v_jpadhold2).w ; make Sonic run to the right
                v_jpadhold2 = 8/*btnR<<8*/;
        }


	//loc_EC70:
	//tst.b	(v_player).w
        //beq.s	loc_EC86
        
        if (player.ID != 0)
        { 
	    //move.w	(v_player+obX).w,d0
            word playerX = player.X;

	    //move.w	(v_limitright2).w,d1
            //addi.w	#$128,d1
            word rightlimit = v_limitright2+0x128;

	    //cmp.w	d1,d0
            //bcs.s	locret_ECEE
            if (rightlimit < playerX)
            {
                //loc_EC86:
		//addq.b	#2,obRoutine(a0)
                obj->Routine = obj->Routine + 2;

                GotThroughAct();
            }
        }
        else
        {
                //loc_EC86:
		//addq.b	#2,obRoutine(a0)
                obj->Routine = obj->Routine + 2;

                GotThroughAct();
        }
    }
}

//; ---------------------------------------------------------------------------
//; Subroutine to	set up bonuses at the end of an	act
//; ---------------------------------------------------------------------------

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||

word TimeBonuses[21] = { 5000, 5000, 1000, 500, 400, 400, 300, 300, 200, 200,
		          200,  200,  100, 100, 100, 100,  50,  50,  50,  50, 0 };

//GotThroughAct:				; XREF: Obj3E_EndAct
void GotThroughAct()
{
    //tst.b	(v_objspace+$5C0).w
    //bne.s	locret_ECEE
    if (objects[22].ID == 0)
    {
        //move.w	(v_limitright2).w,(v_limitleft2).w
        v_limitleft2 = v_limitright2;

	//clr.b	(v_invinc).w	; disable invincibility
        v_invinc = 0;

	//clr.b	(f_timecount).w	; stop time counter
        f_timecount = 0;

	//move.b	#id_GotThroughCard,(v_objspace+$5C0).w
        objects[22].ID = id_GotThroughCard;

        #define plcid_TitleCard 16
	//moveq	#plcid_TitleCard,d0
        //jsr	(NewPLC).l	; load title card patterns
        NewPLC(plcid_TitleCard);

	//move.b	#1,(f_endactbonus).w
        f_endactbonus = 1;

	//moveq	#0,d0
	//move.b	(v_timemin).w,d0
        byte minutes = v_timemin;

	//mulu.w	#60,d0		; convert minutes to seconds
        word minutesinseconds = minutes * 60;
		
        //moveq	#0,d1
	//move.b	(v_timesec).w,d1
        byte seconds = v_timesec;

	//add.w	d1,d0		; add up your time
        word totalseconds = minutesinseconds + seconds;

	//divu.w	#15,d0		; divide by 15
        word scaledseconds = totalseconds / 15;

	//moveq	#$14,d1
        long maxscaledseconds = 0x14;

	//cmp.w	d1,d0		; is time 5 minutes or higher?
        //bcs.s	@hastimebonus	; if not, branch
        if (scaledseconds > maxscaledseconds)
        {
	    //move.w	d1,d0		; use minimum time bonus (0)
            scaledseconds = maxscaledseconds;
        }
	
        //@hastimebonus:
	//add.w	d0,d0
        word bonusindex = scaledseconds*2;

	//move.w	TimeBonuses(pc,d0.w),(v_timebonus).w ; set time bonus
        v_timebonus = TimeBonuses[bonusindex];

	//move.w	(v_rings).w,d0	; load number of rings
        word rings = v_rings;

	//mulu.w	#10,d0		; multiply by 10
        word ringbonus = rings * 10;

	//move.w	d0,(v_ringbonus).w ; set ring bonus
        v_ringbonus = ringbonus;

	//sfx	bgm_GotThrough	; play "Sonic got through" music

    }//locret_ECEE:
    //rts	
}   //; End of function GotThroughAct

//Sign_Exit:	; Routine 8
void Sign_Exit()
{
  //rts	
}
